package com.rosan.installer.util

import android.annotation.SuppressLint
import com.rosan.installer.data.reflect.repo.ReflectRepo
import org.koin.core.component.KoinComponent
import org.koin.core.component.get

object OSUtils : KoinComponent {
    private val reflect = get<ReflectRepo>()

    // Key for MIUI version name
    private const val KEY_MIUI_VERSION_NAME = "ro.miui.ui.version.name"

    // Key for HyperOS version name
    private const val KEY_HYPEROS_VERSION_NAME = "ro.hyperos.version.name"

    // Keys for OPPO OSdkVersion
    private const val KEY_OPLUS_API = "ro.build.version.oplus.api"
    private const val KEY_OPLUS_SUB_API = "ro.build.version.oplus.sub_api"

    /**
     * Checks if the device is running HyperOS.
     */
    fun isHyperOS(): Boolean {
        return !getSystemProperty(KEY_HYPEROS_VERSION_NAME).isNullOrEmpty()
    }

    /**
     * Checks if the device is running MIUI.
     */
    fun isMIUI(): Boolean {
        return !getSystemProperty(KEY_MIUI_VERSION_NAME).isNullOrEmpty()
    }

    /**
     * Get OPPO OSdkVersion.
     * The value is composed of "ro.build.version.oplus.api" and "ro.build.version.oplus.sub_api" joined by a dot.
     * e.g., if api is "30" and sub_api is "1", returns "30.1".
     */
    fun getOplusOSdkVersion(): String? {
        val api = getSystemProperty(KEY_OPLUS_API)
        // If the main API version is missing, it's likely not an applicable device or the property doesn't exist.
        if (api.isNullOrEmpty()) {
            return null
        }

        val subApi = getSystemProperty(KEY_OPLUS_SUB_API)

        // Concatenate with a dot if subApi exists, otherwise return just the api version.
        return if (!subApi.isNullOrEmpty()) {
            "$api.$subApi"
        } else {
            api
        }
    }

    /**
     * Get a system property value using the ReflectRepo
     */
    @SuppressLint("PrivateApi")
    private fun getSystemProperty(key: String): String? {
        try {
            val clz = Class.forName("android.os.SystemProperties")
            // Try public get(key, def) first
            val method = reflect.getMethod(clz, "get", String::class.java, String::class.java)
                ?: reflect.getDeclaredMethod(clz, "get", String::class.java, String::class.java)
                ?: return null

            // It's a static method: pass null as the instance. Use empty string as default.
            val value = method.invoke(null, key, "") as? String
            return value?.takeIf { it.isNotEmpty() }
        } catch (t: Throwable) {
            t.printStackTrace()
        }
        return null
    }
}
